package com.dongbao.util;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import org.jetbrains.idea.maven.utils.Path;
import org.objenesis.strategy.StdInstantiatorStrategy;

import java.io.*;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.Map;

/**
 * Kryo Utils
 * <p/>
 */
public  class KryoUtil {

    /**
     * （池化Kryo实例）使用ThreadLocal
     */
    private static final ThreadLocal<Kryo> kryos = new ThreadLocal<Kryo>() {
        @Override
        protected Kryo initialValue() {
            Kryo kryo = new Kryo();
            /**
             * 不要轻易改变这里的配置,更改之后，序列化的格式就会发生变化，
             * 上线的同时就必须清除 Redis 里的所有缓存，
             * 否则那些缓存再回来反序列化的时候，就会报错
             */
            //支持对象循环引用（否则会栈溢出）
            kryo.setReferences(true); //默认值就是 true，添加此行的目的是为了提醒维护者，不要改变这个配置
            //不强制要求注册类（注册行为无法保证多个 JVM 内同一个类的注册编号相同；而且业务系统中大量的 Class 也难以一一注册）
            kryo.setRegistrationRequired(false); //默认值就是 false，添加此行的目的是为了提醒维护者，不要改变这个配置
            //Fix the NPE bug when deserializing Collections.
            ((Kryo.DefaultInstantiatorStrategy) kryo.getInstantiatorStrategy()).setFallbackInstantiatorStrategy(new StdInstantiatorStrategy());
            return kryo;
        }
    };
    /**
     *
     * @param filepath
     * @param obj
     *            需序列化的 JAVA 基础对象，List Map
     */
    public static void writeKryo(String filepath, String fileName, Object obj) {
        OutputStream os = null;
        Output output = null;
        try {
            File file = new File(filepath);
            if (!file.exists()) {
//                FileUtil.createDier(filepath);
                Files.createDirectories((java.nio.file.Path) new Path(filepath));
            }
            file = new File(filepath +"\\"+ fileName);
            if (!file.exists()) {
                file.createNewFile();
            }
            os = new FileOutputStream(file);
            output = new Output(os);// kryo序列化输出流
            KryoSingleton.getInstance().writeClassAndObject(output, obj);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(output, os);
        }
    }

    public static <T> T readKryo(String filepath) {
        InputStream is = null;
        Input input = null;
        T o = null;
        try {
            is = new FileInputStream(filepath);
            input = new Input(is, 1024 * 2);
            o = (T) KryoSingleton.getInstance().readClassAndObject(input);
        } catch (IOException e) {
            throw new IllegalAccessError(e.getMessage());
        } finally {
            close(is, input);
        }
        return o;
    }

    /**
     * 关闭Closeable
     *
     * @param iss
     */
    public static void close(Closeable... iss) {
        for (Closeable is : iss) {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                }
            }
        }
    }

    /**
     * 序列化
     *
     * @param filepath
     * @param obj
     * @param kryo
     */
    public static void writeKryo(String filepath, Object obj, Kryo kryo) {
        OutputStream os = null;
        Output output = null;
        try {
            File file = new File(filepath);
            os = new FileOutputStream(file);
            output = new Output(os);// kryo序列化输出流
            kryo.writeClassAndObject(output, obj);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(output, os);
        }


    }


    public static void main(String[] args) {
        String name="张三";
        Map<String,Object> map=new HashMap<String,Object>();
        map.put("name","张三");
        /* 序列化存储文件 */
        KryoUtil.writeKryo("F:\\test\\","kryo.cache",name);
        /* 读取序列化文件 */
        String name2 = KryoUtil.readKryo("F:\\test\\kryo.cache");
        System.out.println("name2:"+name2);
    }

}

